﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.DataAnnotations;

namespace Niagara.Core
{
  /// <summary>
  /// AttributeMetadataProvider that retrieves metadata based on reflection 
  /// attributes.
  /// </summary>
  public class ReflectionAttributeMetadataProvider : IAttributeMetadataProvider
  {
    #region Fields
    Assembly _reflectedAssembly;
    #endregion // Fields

    #region Construction
    /// <summary>
    /// Initializes a new instance of the <see cref="ReflectionAttributeMetadataProvider"/> class.
    /// </summary>
    /// <param name="reflectedAssembly">The reflected assembly.</param>
    public ReflectionAttributeMetadataProvider(Assembly reflectedAssembly)
    {
      _reflectedAssembly = reflectedAssembly;
    }
    #endregion // Construction

    #region IAttributeMetadataProvider
    /// <summary>
    /// Gets the attributes for a specific property on a type.
    /// </summary>
    /// <param name="typeName">Name of the type.</param>
    /// <param name="propertyName">Name of the property.</param>
    /// <returns>List of Attributes.</returns>
    public IEnumerable<Attribute> GetPropertyAttributes(string typeName, string propertyName)
    {
      Type testType = Type.GetType(string.Concat(typeName, ", ", _reflectedAssembly.FullName));
      if (testType == null)
      {
        var simpleTypeName = typeName.LastIndexOf('.') > -1 ? typeName.Substring(typeName.LastIndexOf('.') + 1) : typeName;
        testType = _reflectedAssembly.GetTypes().Where(t => t.Name == simpleTypeName).FirstOrDefault();
      }

      if (testType != null)
      {
        // Test for MetadataTypeAttribute
        object metadataTypeAttribute = testType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
        if (metadataTypeAttribute != null)
        {
          testType = ((MetadataTypeAttribute)metadataTypeAttribute).MetadataClassType;
        }

        // Find the Property information
        var prop = testType.GetProperty(propertyName);
        if (prop != null)
        {
          var results = prop.GetCustomAttributes(false);
          // Only return ValidationAttributes
          var filter = new Func<Attribute, bool>(a => 
            a.GetType().IsSubclassOf(typeof(ValidationAttribute)) 
          );
          return results.Cast<Attribute>().Where(filter);
        }
      }
      return new Attribute[] { };
    }

    /// <summary>
    /// Gets the attributes for a particular type.
    /// </summary>
    /// <param name="typeName">Name of the type.</param>
    /// <returns>List of Attributes.</returns>
    public IEnumerable<Attribute> GetTypeAttributes(string typeName)
    {
      return new Attribute[] { };
    }
    #endregion //IAttributeMetadataProvider
  }
}
